#include "user_main.h"

#include "nvs_flash.h"
#include "nvs.h"

static const char *TAG = "max7219_main";

#if SUPPORT_FIRMWARE_OTA
static const char *ota_version_url = "http://norep.gitee.io/ota/ota_test/version";
static const char *ota_image_url = "http://norep.gitee.io/ota/ota_test/ota.bin";
#endif

static const char *temperature_sensor_config_topic="homeassistant/sensor/P1T/config";
static const char *temperature_sensor_config_payload="{\"device_class\":\"temperature\",\"name\":\"P1Temperature\",\"unique_id\":\"P1Temperature\",\"state_topic\":\"homeassistant/sensor/P1/state\",\"unit_of_measurement\":\"C\",\"value_template\":\"{{ value_json.temperature}}\"}";

static const char *humidity_sensor_config_topic="homeassistant/sensor/P1H/config";
static const char *humidity_sensor_config_payload="{\"device_class\":\"humidity\",\"name\":\"P1Humidity\",\"unique_id\":\"P1Humidity\",\"state_topic\":\"homeassistant/sensor/P1/state\",\"unit_of_measurement\":\"%\",\"value_template\":\"{{ value_json.humidity}}\"}";

static const char *update_data_topic = "homeassistant/sensor/P1/state";

static int shortdown(void)
{
    ESP_LOGW(TAG, "===== SHOART DOWN =====");
    return 0;
}
    
static int longdown(void)
{
    ESP_LOGW(TAG, "===== LONG DOWN =====");
    return 0;
}

static void WIFI_Connect_cb(char *ip)
{
    system_status_t *sys_sta = get_sys_sta();
    sys_sta->network_sta = 1;
    ESP_LOGW(TAG, "wifi connect : %s", ip);
}

static void WIFI_Disconnect_cb(void)
{
    system_status_t *sys_sta = get_sys_sta();
    sys_sta->network_sta = 0;
    ESP_LOGW(TAG, "wifi disconnect");
    write_str_to_buf(0 , 0, "Reboot", 6, SIZE_F5x7);
    LedRefresh();
    sys_sta->reboot_flag = 1;
}

static httpd_handle_t server = NULL;

static int user_get_cb(httpd_req_t *req)
{
    httpd_resp_send(req, index_html_start, index_html_end - index_html_start);
    return 0;
}

static int user_post_cb(httpd_req_t *req, char *content, int len)
{
    system_status_t *sys_sta = get_sys_sta();
    char ssid[32];
    char passwd[32];
    int ret = httpd_query_key_value(content,"ssid",ssid,sizeof(ssid));
    if(ret == ESP_OK) {
        printf("ssid = %s\n",ssid);
    }
    else {
        printf("error = %d\n",ret);
    }

    ret = httpd_query_key_value(content,"password",passwd,sizeof(passwd));
    if(ret == ESP_OK) {
        printf("password = %s\n",passwd);
    }
    else {
        printf("error = %d\n",ret);
    }

    if (strlen(ssid) && strlen(passwd)) {
        my_nvs_wifi_info_set(ssid, passwd);
        write_str_to_buf(0 , 0, "Reboot", 6, SIZE_F5x7);
        LedRefresh();
        sys_sta->reboot_flag = 1;
    }
    httpd_resp_send(req, save_html_start, save_html_end - save_html_start);
    return 0;
}

static void WIFI_AP_STAConnect_cb(void)
{
    my_http_cb_t user_cb;
    user_cb.get_cb = user_get_cb;
    user_cb.post_cb = user_post_cb;
    my_http_server_set_callback(user_cb);
    ESP_LOGW(TAG, "WIFI_AP_STAConnect_cb");
    if (server == NULL) {
        ESP_LOGW(TAG, "Starting webserver");
        server = my_start_webserver();
    }
}

static void WIFI_AP_STADisconnect_cb(void)
{
    ESP_LOGW(TAG, "WIFI_AP_STADisconnect_cb");
}

static void Networl_init(void)
{
    my_wifi_t wifi_info = {};
    wifi_mode_t wifi_init_mode = WIFI_MODE_AP;

    if (my_nvs_wifi_info_get(&wifi_info)) {

        memcpy(wifi_info.ssid, "esp8266", strlen("esp8266"));
        memset(wifi_info.password, 0, sizeof(wifi_info.password));
        wifi_info.max_connection = 1;

        wifi_info.ap_staconnect_cb = WIFI_AP_STAConnect_cb;
        wifi_info.ap_stadisconnect_cb = WIFI_AP_STADisconnect_cb;
        write_str_to_buf(0 , 0, "AP Net", 6, SIZE_F5x7);
        LedRefresh();
        wifi_init_mode = WIFI_MODE_AP;
    } else {
        wifi_info.connect_cb = WIFI_Connect_cb;
        wifi_info.disconnect_cb = WIFI_Disconnect_cb;

        write_str_to_buf(0 , 0, "StaNet", 6, SIZE_F5x7);
        wifi_init_mode = WIFI_MODE_STA;
    }
    my_wifi_init(&wifi_info, wifi_init_mode);
}

/* DHT11控制IO操作函数 */
static void DHT11_out_cb(int sta)
{
    gpio_set_level(DHT11_GPIO, sta);
}

static int DHT11_in_cb(void)
{
    return gpio_get_level(DHT11_GPIO);
}

/* DHT11控制IO模式配置 */
static void DHT11_OutPut_Mode_cb(void)
{
    gpio_set_direction(DHT11_GPIO, GPIO_MODE_OUTPUT);
}

static void DHT11_InPut_Mode_cb(void)
{
    gpio_set_direction(DHT11_GPIO, GPIO_MODE_INPUT);
}

/* DHT11 us 级延时函数 */
static void DHT11_delay_us_cb(uint32_t us)
{
    uint16_t ms = 0;
    if (us >= 10000) {
        ms = us / 1000;
        vTaskDelay(ms / portTICK_RATE_MS);
        ets_delay_us((uint16_t)(us - (ms * 1000)));
    } else {
        ets_delay_us((uint16_t)us);
    }
}

static void user_DHT11_Init()
{	
    gpio_config_t IO_config;

    IO_config.pin_bit_mask = GPIO_DHT11_PIN_MASK;
    IO_config.mode = GPIO_MODE_OUTPUT;
    IO_config.pull_up_en = GPIO_PULLUP_ENABLE;
    IO_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
    IO_config.intr_type = GPIO_INTR_DISABLE;
    gpio_config(&IO_config);

     DHT11_init_t init_cb;
    init_cb.delay_us_cb = DHT11_delay_us_cb;
    init_cb.in_cb = DHT11_in_cb;
    init_cb.out_cb = DHT11_out_cb;
    init_cb.in_mode_cb = DHT11_InPut_Mode_cb;
    init_cb.out_mode_cb = DHT11_OutPut_Mode_cb;

    uint8_t ret = 0;
    ret = DHT11_Init(init_cb);

    if (ret != 0) {
        printf("Not found DHT11\n");
    }
}


static void MAX7219_Write_Data(uint8_t *data, uint16_t len)
{
    my_spi_write(data, len);
}

static void write_max7219_time(uint8_t h, uint8_t m, uint8_t s)
{
    char buf[10] = {};
    uint8_t x = 1, y = 0;
    
    if (h < 7) {
        clear_show();
    } else {
        snprintf(buf, sizeof(buf), "%02d:%02d", h, m);
        write_str_to_buf(x, y, buf, strlen(buf), SIZE_F6X8);
        LedRefresh();
    }
}

uint8_t temperature = 0;  	    
uint8_t humidity = 0;

static void refresh_task(void *argv)
{
    uint8_t ret = 0;

    uint8_t temperature_b = 0;  	    
    uint8_t humidity_b = 0;

    system_status_t *sys_sta = get_sys_sta();
    uint8_t s_old = 0;

    while (sys_sta->network_sta == 0)
    {
        vTaskDelay(1000/portTICK_RATE_MS);
    }
    while (timeinfo.tm_hour == 0 || timeinfo.tm_hour == 8)
    {
        write_str_to_buf(0 , 0, "NTP...", 6, SIZE_F5x7);
        LedRefresh();
        vTaskDelay(1000/portTICK_RATE_MS);
    }
    clear_show();
    while (1)
    {
        if (s_old != timeinfo.tm_sec){
            write_max7219_time(timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
            s_old = timeinfo.tm_sec;
        }
        vTaskDelay(1000/portTICK_RATE_MS);
        ret = DHT11_Read_Data(&temperature_b, &humidity_b);
        if (ret != 0) {
            printf("Not found DHT11\n");
        } else {
            temperature = temperature_b;
            humidity = humidity_b;
            printf("T:%d H:%d \n", temperature, humidity);
        }
    }
}

static void MY_MQTT_Connect_cb(void)
{
    printf("MQTT Connect SUCCESS\n");
    my_mqtt_publish(temperature_sensor_config_topic, temperature_sensor_config_payload, 0, 1, 1);
    my_mqtt_publish(humidity_sensor_config_topic, humidity_sensor_config_payload, 0, 1, 1);
}

static void MY_MQTT_DISConnect_cb(void)
{
}

static void MY_MQTT_RecData_cb(char *topic, int topic_len, char *data, int data_len)
{
}

static void init_my_mqtt()
{
    my_mqtt_init_info_t mqtt_init_cfg = {0};

    mqtt_init_cfg.host = "pi.oynote.top";
    mqtt_init_cfg.port = 1883;

    mqtt_init_cfg.connect_cb = MY_MQTT_Connect_cb;
    mqtt_init_cfg.disconnect_cb = MY_MQTT_DISConnect_cb;
    mqtt_init_cfg.received_cb = MY_MQTT_RecData_cb;

    my_mqtt_init(mqtt_init_cfg);
}

static void mqtt_task(void *arg)
{
    system_status_t *sys_sta = get_sys_sta();
    while (sys_sta->network_sta != 1)
    {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    init_my_mqtt();

    char buf[256];

    while (temperature == 0 && humidity == 0)
    {
        printf("temperature == 0 && humidity == 0");
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }

    while (1)
    {
        while (sys_sta->network_sta)
        {

            memset(buf, 0, sizeof(buf));

            snprintf(buf, sizeof(buf), "{\"temperature\":%d,\"humidity\":%d}", temperature, humidity);
            printf("buf:%s\n", buf);
            my_mqtt_publish(update_data_topic, buf, 0, 1, 1);

            vTaskDelay(5000 / portTICK_PERIOD_MS);
        }
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void app_main()
{
    int ret = 0;

    system_status_t *sys_sta = get_sys_sta();
    const esp_app_desc_t *app_desc = esp_ota_get_app_description();
    sys_sta->version = (char *)app_desc->version;
    ESP_LOGI(TAG, "app_version:%s", sys_sta->version); 

#if SUPPORT_FIRMWARE_OTA
    sys_sta->ota_version_path = ota_version_url;
    sys_sta->ota_image_path = ota_image_url;
#endif

    system_init();
    
    printf("free_heap_size: %d KB\n", esp_get_free_heap_size() / 1024);
    printf("minimum_free_heap_size: %d KB\n", esp_get_minimum_free_heap_size() / 1024);

    set_key_shortDown_callback(200, shortdown);
    set_key_longDown_callback(2000, longdown);

    my_spi_init(NULL);
    ret = max7219Init(MAX7219_Write_Data, 4);
    if (ret){
        ESP_LOGE(TAG,"max7219Init err");
    }
    
    user_DHT11_Init();

    ESP_LOGI(TAG,"create refresh task");
    new_task(refresh_task, "refresh_task", 1024 * 2, NULL, 24);

    ESP_LOGI(TAG, "start connect wifi...");
    write_str_to_buf(0 , 0, "Net...", 6, SIZE_F5x7);
    LedRefresh();
    Networl_init();
    ESP_LOGI(TAG, "Run");

    ESP_LOGI(TAG,"create update mqtt task");
    new_task(mqtt_task, "mqtt_task", 1024 * 2, NULL, 25);
}
